package main

import (
	"context"
	"github.com/labstack/echo/v4"
	"github.com/labstack/echo/v4/middleware"
	"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
	"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
	"go.opentelemetry.io/otel/propagation"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
	"go.opentelemetry.io/otel/trace"

	"go.opentelemetry.io/otel/sdk/resource"
	semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
	"log"
	"time"

	"net/http"
)

// ./j--set=receivers.otlp.protocols.grpc.endpoint=0.0.0.0:4317

func init() {
	client := otlptracegrpc.NewClient(
		otlptracegrpc.WithEndpoint("127.0.0.1:4317"),
		otlptracegrpc.WithInsecure(),
	)
	exp, err := otlptrace.New(context.Background(), client)
	if err != nil {
		log.Fatalf("otlptrace.New: %v", err)
		return
	}

	res, err := resource.Merge(
		resource.Default(),
		resource.NewWithAttributes(
			semconv.SchemaURL,
			semconv.ServiceName("app1"),
		),
	)
	if err != nil {
		log.Fatalf("otlptrace.New: %v", err)
		return
	}

	// 创建追踪器提供者
	tp := sdktrace.NewTracerProvider(
		sdktrace.WithBatcher(exp),
		sdktrace.WithResource(res),
	)
	otel.SetTracerProvider(tp)
	otel.SetTextMapPropagator(propagation.TraceContext{})
}

func main() {

	e := echo.New()

	e.Use(middleware.Logger())
	//e.Use(otelecho.Middleware("service-name-app1"))

	e.GET("/app1", func(c echo.Context) error { // 获取 Tracer
		tracer := otel.Tracer("ServiceA")

		// 创建父 span
		ctx, parentSpan := tracer.Start(c.Request().Context(), "parent-span", trace.WithSpanKind(trace.SpanKindServer))
		defer parentSpan.End()
		parentSpan.SetAttributes(
			semconv.ServiceName("ServiceA"),
			semconv.ServiceNamespace("service-a-namespace"),
			semconv.ServiceVersion("1.0.0"),
		)

		client := &http.Client{
			Transport: otelhttp.NewTransport(http.DefaultTransport),
		}

		client.Timeout = time.Second * 10

		req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://localhost:8082/app2", nil)
		if err != nil {
			log.Println(err)
		}
		resp, err := client.Do(req)
		if err != nil {
			log.Println(err)
		}
		defer resp.Body.Close()

		log.Println("calling app2")
		return c.JSON(http.StatusOK, map[string]interface{}{
			"hello": "world",
		})
	})

	err := e.Start(":8081")
	if err != nil {
		log.Fatal(err)
		return
	}

}
